<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<script type="text/javascript">
			// 状态管理 + 发布订阅（回调函数缓存）

			function MyPromise(execution) {
				// 静态属性（常量）
				MyPromise.PENDING = 'pending'
				MyPromise.FULFILLED = 'fulfilled'
				MyPromise.REJECTED = 'rejected'

				this.status = MyPromise.PENDING // 状态
				this.reason = null // 失败原因
				this.value = null // 成功返回值
				// 收集依赖缓存(函数)
				this.resolveDeps = []
				this.rejectDeps = []
				// 以上的遍历也可设为私有变量，再添加get/set方法，这里为简化没做

				// this缓存
				var self = this

				// 成功回调
				function resolve(res) {
					// 判断状态
					if (self.status === MyPromise.PENDING) {
						self.value = res
						self.status = MyPromise.FULFILLED

						// 这种方式可以遍历数组且执行后可以清空数组，简化清空数组的步骤
						while (self.resolveDeps.length) {
							// 发布给所有订阅
							self.resolveDeps.shift()(res)
						}
					}
				}

				// 失败回调
				function reject(err) {
					// 判断状态
					if (self.status === MyPromise.PENDING) {
						self.reason = err
						self.status = MyPromise.REJECTED
						// 发布给订阅
						while (self.rejectDeps.length) {
							self.rejectDeps.shift()(err)
						}
					}
				}


				// 判断参数传入是否是函数
				if (typeof execution === 'function') {

					// 捕获错误
					try {
						// 执行传入的执行器
						execution(resolve, reject)

					} catch (err) {
						reject(err)
					}

				} else {
					throw 'MyPromise 的参数必须为函数。'
				}
			}


			MyPromise.prototype.then = function(onResolved, onRejected) {
				if ((onRejected && typeof onRejected !== 'function') || typeof onResolved !== 'function') {
					throw 'then 方法的参数必须为函数。'
				}

				// then方法链式 返回新promise
				return new MyPromise((resolve, reject) => {

					const resolvedCb = (val) => {
						let nextVal = onResolved(val);

						if (nextVal instanceof MyPromise) { // promise对象

							nextVal.then(resolve, reject)

						} else { // 普通值

							resolve(nextVal);

						}
					}

					const rejectedCb = (reason) => {
						let nextVal = onRejected(reason);

						if (nextVal instanceof MyPromise) { // promise对象

							nextVal.then(resolve, reject)

						} else { // 普通值

							resolve(nextVal)

						}
					}

					// 执行器是异步操作时，status还是pending，
					// 所以此时并不知道是成功还是失败回调，那么这里就需要把这两个回调
					// 存储起来
					this.resolveDeps.push(resolvedCb)
					this.rejectDeps.push(rejectedCb)
				})
			}

			MyPromise.prototype.catch = function(onRejected) {
				if (typeof onRejected === 'function') {
					// 收集依赖
					this.addRejectDeps(onRejected)
				} else {
					throw 'catch 方法的参数必须为函数。'
				}
			}

			MyPromise.prototype.finally = function() {}

			MyPromise.prototype.all = function() {}

			MyPromise.prototype.allSettled = function() {}

			var demo = function() {
				return new MyPromise((resolve, reject) => {
					setTimeout(() => {
						resolve(123435)
					}, 1000)
				})
			}
			demo().then((res) => {
				console.log('=========res', res)
				return new MyPromise((resolve, reject) => {
					setTimeout(() => {
						resolve('erersadad')
					}, 1000)
				})
			}).then((res) => {
				console.log('=========res2', res)
			})
		</script>
	</body>
</html>
